#pragma once
#include <jsoncpp/json/json.h>
#include <iostream>
#include <string>
#include <sstream>
#include <memory>
#include <cstring>
#include <fstream>
#include <sys/types.h>
#include <sys/stat.h>
#include <unistd.h>

//-------------------------------------------  File Util ----------------------------------------------------

// 文件操作工具类
namespace vod
{
    class FileUtil
    {
    public:
        FileUtil(std::string name = "") : name_(name)
        {
        }

        bool Exists(const std::string &filepath);      // Determine if the file exists
        size_t FileSize();                             // Get file size
        bool ReadFileData(std::string *out);           // out is 输出型参数
        bool WriteFileData(const std::string &in);     // in is 输入型参数
        bool CreateDirectory(const std::string &name); // create subdirectory

    private:
        std::string name_; // file path name
    };

    bool FileUtil::Exists(const std::string &filepath)
    {
        int ret = access(filepath.c_str(), F_OK); // F_OK 用于检测name_是否存在
        if (ret < 0)
        {
            std::cout << "The file does not exist. error masage: " << strerror(errno) << std::endl;
            return false;
        }
        return true;
    }

    size_t FileUtil::FileSize()
    {
        if (Exists(name_) == false)
            return 0;

        struct stat buffer;
        memset(&buffer, 0, sizeof(buffer));
        int ret = stat(name_.c_str(), &buffer); // Get file All Properties
        if (ret < 0)
        {
            std::cout << "Get file All Properties error: " << strerror(errno) << std::endl;
            return 0;
        }
        return buffer.st_size;
    }

    bool FileUtil::ReadFileData(std::string *out)
    {
        std::ifstream ifs(name_, std::ios::binary | std::ios::in); // 二进制方式打开
        if (ifs.is_open() == false)
        {
            std::cout << "open file failed" << std::endl;
            return false;
        }
        size_t filesize = FileSize();
        out->resize(filesize);
        ifs.read(&((*out)[0]), filesize);
        if (ifs.good() == false)
        {
            std::cout << "read file failed" << std::endl;
            ifs.close();
            return false;
        }
        ifs.close();
        return true;
    }

    bool FileUtil::WriteFileData(const std::string &in)
    {
        std::ofstream ofs(name_, std::ios::binary | std::ios::out);
        if (ofs.is_open() == false)
        {
            std::cout << "open file failed" << std::endl;
            return false;
        }
        ofs.write(in.c_str(), in.size());
        if (ofs.good() == false)
        {
            std::cout << "write file failed" << std::endl;
            ofs.close();
            return false;
        }
        ofs.close();
        return true;
    }

    bool FileUtil::CreateDirectory(const std::string &dirpath)
    {
        if (Exists(dirpath))
            return true;
        umask(0);
        int ret = mkdir(dirpath.c_str(), 0777);
        if (ret < 0)
        {
            std::cout << "create directory falied. error massage: " << strerror(errno) << std::endl;
            return false;
        }
        return true;
    }
}

//-------------------------------------------  Json Util ----------------------------------------------------

// Json序列化和反序列化工具类
namespace vod
{    
    // demo -> PATH: /home/lyh/Json_Demodemo.cpp -- In have api
    class JsonUtil
    {
    public:
        static bool Serialize(Json::Value &root, std::string *out)
        {
            Json::StreamWriterBuilder swb; // StreamWriterBuilder继承StreamWriter
            std::unique_ptr<Json::StreamWriter> sw(swb.newStreamWriter()); // StreamWriter不能定义，它是一个接口类 -- 纯虚函数
            std::stringstream ss;
            int ret = sw->write(root, &ss); // write第二次参数为输出型，转化成功自动填充到这里
            if (ret != 0)
            {
                std::cout << "write failed!\n";
                return false;
            }
            *out = ss.str();
            return true;
        }

        static bool Deserialize(const std::string &in, Json::Value *root)
        {
            Json::CharReaderBuilder crb; // 与序列化接口一只，也是继承了CharReader
            std::string SerData(in);
            std::string errs; // error massage
            std::unique_ptr<Json::CharReader> pcrb(crb.newCharReader());
            bool IsSucess = pcrb->parse(SerData.c_str(), SerData.c_str() + strlen(SerData.c_str()), root, &errs);
            if (IsSucess == false)
            {
                std::cout << "parse error: " << errs << std::endl;
                return false;
            }
            return true;
        }
    };
}